﻿#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WaveEngine.Common.Math;
using WaveEngine.Extensions.ITasks;
using WaveEngine.Framework;
using WaveEngine.Framework.Animation;
using WaveEngine.Framework.Graphics; 
#endregion

namespace WaveEngine.Extensions.Behaviors
{
    public class MovementBehavior : Component
    {
        [RequiredComponent]
        private Transform2D transform2D = null;

        [RequiredComponent]
        private AnimationUI animationUI = null;

        private Scene scene;

        private SingleAnimation xAnimation;
        private SingleAnimation yAnimation;
        private SingleAnimation rotationAnimation;
        private SingleAnimation scaleAnimation;

        public MovementBehavior()
        {
            this.xAnimation = new SingleAnimation();
            this.yAnimation = new SingleAnimation();
            this.rotationAnimation = new SingleAnimation();
            this.scaleAnimation = new SingleAnimation();
        }

        protected override void ResolveDependencies()
        {
            base.ResolveDependencies();

            this.scene = this.Owner.Scene;
        }

        public ITask CreateMovementTask(Vector2 destination, TimeSpan duration, IEasingFunction EasingFunction = null)
        {
            return this.scene.CreateParallelTasks(
                        this.CreateXMovementTask(destination.X, duration, EasingFunction),
                        this.CreateYMovementTask(destination.Y, duration, EasingFunction))
                        .WaitAll();
        }

        public ITask CreateXMovementTask(float destination, TimeSpan duration, IEasingFunction EasingFunction = null)
        {
            return this.scene.CreateActionTask(() =>
                {
                    this.xAnimation.From = this.GetRelativeX();
                    this.xAnimation.To = destination;
                    this.xAnimation.Duration = duration;
                    this.xAnimation.EasingFunction = EasingFunction;
                })
                .ContinueWithSingleAnimation(this.xAnimation, this.animationUI, Transform2D.XProperty);
        }

        public ITask CreateYMovementTask(float destination, TimeSpan duration, IEasingFunction EasingFunction = null)
        {
            return this.scene.CreateActionTask(() =>
                {
                    this.yAnimation.From = this.GetRelativeY();
                    this.yAnimation.To = destination;
                    this.yAnimation.Duration = duration;
                    this.yAnimation.EasingFunction = EasingFunction;
                })
                .ContinueWithSingleAnimation(this.yAnimation, this.animationUI, Transform2D.YProperty);
        }

        public ITask CreateRotationMovementTask(float destination, TimeSpan duration, IEasingFunction EasingFunction = null)
        {
            return this.scene.CreateActionTask(() =>
                {
                    this.rotationAnimation.From = this.transform2D.Rotation;
                    this.rotationAnimation.To = destination;
                    this.rotationAnimation.Duration = duration;
                    this.rotationAnimation.EasingFunction = EasingFunction;
                })
                .ContinueWithSingleAnimation(this.rotationAnimation, this.animationUI, Transform2D.RotationProperty);
        }

        public ITask CreateScaleMovementTask(float destination, TimeSpan duration, IEasingFunction EasingFunction = null)
        {
            return this.scene.CreateActionTask(() =>
                {
                    this.scaleAnimation.From = this.transform2D.XScale;
                    this.scaleAnimation.To = destination;
                    this.scaleAnimation.Duration = duration;
                    this.scaleAnimation.EasingFunction = EasingFunction;
                })
                .ContinueWith(
                    this.scene.CreateSingleAnimationTask(this.scaleAnimation, this.animationUI, Transform2D.XScaleProperty),
                    this.scene.CreateSingleAnimationTask(this.scaleAnimation, this.animationUI, Transform2D.YScaleProperty))
                .WaitAll();
        }

        public float GetRelativeX()
        {
            float result = this.transform2D.X;

            if (this.Owner.Parent != null)
            {
                var parentTransform = this.Owner.Parent.FindComponent<Transform2D>();

                result -= parentTransform.X;
            }

            return result;
        }

        public float GetRelativeY()
        {
            float result = this.transform2D.Y;

            if (this.Owner.Parent != null)
            {
                var parentTransform = this.Owner.Parent.FindComponent<Transform2D>();

                result -= parentTransform.Y;
            }

            return result;
        }
    }
}
